import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  forwardRef,
  useImperativeHandle,
} from 'react';
import ReactDOM from 'react-dom';
import { Button, Dropdown, message, Tooltip } from 'antd';
import { ProCard, ProTable } from '@ant-design/pro-components';
import type { ProColumns, ProTableProps } from '@ant-design/pro-components';
import { useHistory } from '@/hooks/useHistory';
import Filter, { type FilterHandler } from './Filter';
import { cloneDeep, isBoolean } from 'lodash';
import {
  AreaChartOutlined,
  ProjectOutlined,
  SettingOutlined,
  TableOutlined,
} from '@ant-design/icons';
import Exports, { type ExportHandler } from './Exports';
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
import { destroyTooltipElementOnHide } from '@/utils/helpers';
import { AnimatePresence, motion } from 'framer-motion';
import CardMode, { CardModeProps } from './CardMode';
import ChartMode from './ChartMode';
import './index.less';

export interface TableElementRef {
  getTableList: (queryFormParams?: any) => void;
  filterInstance: FilterHandler | null;
}

export interface TableElementProps extends ProTableProps<any, any> {
  columns: ProColumns<any>[]; // 表格列
  queryMethod?: (data: any) => Promise<any>; // 后端接口
  queryParams?: any; // 后端接口参数
  queryFormParamsFormatter?: (queryParams?: any) => any; // 自定义重写后端接口参数
  filterQueryKey?: string; // 高级过滤组件记录到URL中的key
  filterSyncUrl?: boolean; // 是否将高级过滤的值记录到URL中
  syncURL?: boolean; // 是否将后端接口参数记录到URL中
  filterParamsFormatter?: (filter: any[], params: any) => any[]; //  自定义重写高级过滤参数(用于添加或者移出一些参数)
  asyncPagination?: boolean; // 是否采用后端的异步分页
  extra?: any[]; // 自定义按钮（置于右侧）
  startExtra?: any[]; // 自定义按钮 （置于左侧）
  scrollX?: number; // 表格横向滚动宽度
  header?: React.ReactNode; // 表格头部
  headerRender?: (dataSource: any[], loading: boolean) => React.ReactNode; //自定义表格卡片的标题渲染
  showFilter?: boolean; // 是否显示高级过滤
  showExport?: boolean; // 是否显示导出按钮
  showFullScreen?: boolean; // 是否显示全屏按钮
  showFeishuExport?: boolean; // 是否显示飞书导出按钮
  feishuExportProps?: {
    // 飞书导出按钮属性
    columns: any[]; // 导出的列
  };
  exportProps?: {
    exportApi?: (params: any) => Promise<any>; // 导出接口
    [key: string]: any;
  }; // 导出按钮属性
  filterProps?: Record<string, any>; // 高级过滤组件属性
  ref?: React.Ref<TableElementRef>;
  dataNumberDecimal?: boolean | number; // data中的数字是否保留小数
  showDisplayMode?: boolean; // 是否显示显示模式按钮
  isTabsTable?: boolean; // 是否是TabsTable
  tableCardProps?: Record<string, any>; // 表格卡片属性
  cardModeProps?: Partial<CardModeProps>; // 卡片模式属性
}

const TableElement = forwardRef<TableElementRef, TableElementProps>((props, ref) => {
  const {
    columns,
    headerRender,
    header,
    request,
    search,
    extra = [],
    startExtra = [],
    asyncPagination = false,
    showFilter = true,
    showExport = true,
    showFullScreen = true,
    filterSyncUrl = true,
    syncURL = false,
    filterQueryKey = 'filter',
    queryFormParamsFormatter,
    filterParamsFormatter,
    showFeishuExport = true,
    feishuExportProps,
    queryMethod,
    queryParams,
    scrollX = 1200,
    dataSource: dataSourceProps,
    exportProps,
    dataNumberDecimal = 2,
    showDisplayMode = true,
    isTabsTable = false,
    cardBordered,
    cardProps,
    filterProps = {},
    tableCardProps = {},
    cardModeProps = {},
    ...rest
  } = props;
  const { navigate, location } = useHistory();
  const [dataSource, setDataSource] = useState<any[]>([]);
  const [dataList, setDataList] = useState<any[]>([]);
  const [exportLoading, setExportLoading] = useState<boolean>(false);
  const [spin, setSpin] = useState<boolean>(false);
  const filterRef = useRef<FilterHandler>(null);
  const exportRef = useRef<ExportHandler>(null);
  const tableElementRef = useRef<HTMLDivElement>(null);
  const [isFullScreen, setIsFullScreen] = useState<boolean>(false);
  const [selectRowIndex, setSelectRowIndex] = useState<number>(-1);
  const [paginateConfig, setPaginateConfig] = useState<{
    current: number;
    pageSize: number;
    pageCount: number;
    sort?: string;
  }>({
    current: Number(location.query?.current as string) || 1,
    pageSize: Number(location.query?.pageSize as string) || 10,
    pageCount: 0,
    sort: (location.query?.sort as string) || undefined,
  });

  const sortDataInfo = useMemo(() => {
    const sort = paginateConfig.sort;
    if (sort) {
      const sortArr = sort.split(' ');
      return {
        field: sortArr[0],
        order: sortArr[1] === 'ASC' ? 'ascend' : 'descend',
      };
    }
    return {};
  }, [paginateConfig.sort]);
  const [displayMode, setDisplayMode] = useState<string>('table');
  const { exportApi, ...restExportProps } = exportProps || {};

  const handleFullScreen = () => {
    const newIsFullScreen = !isFullScreen;
    setIsFullScreen(newIsFullScreen);
    setTimeout(() => {
      // const element = tableElementRef.current;
      if (newIsFullScreen) {
        // element?.classList.add('full-screen');
        document.body.style.overflow = 'hidden';
      } else {
        // element?.classList.remove('full-screen');
        document.body.style.overflow = 'auto';
      }
      destroyTooltipElementOnHide();
    }, 50);
  };


  const formatColumnItem = useCallback(
    (column: any) => {
      const childrenItem = {
        ...column,
      };


      if (!childrenItem.width) childrenItem.width = 250;

      if (asyncPagination && column.dataIndex === sortDataInfo.field) {
        childrenItem.sortOrder = sortDataInfo.order;
      }

      return childrenItem;
    },
    [asyncPagination, sortDataInfo.field, sortDataInfo.order],
  );

  const columnsModified = useMemo(() => {
    return columns.map((column: any) => {
      if (column.children) {
        return {
          ...column,
          children: column.children.map(formatColumnItem),
        };
      }
      return formatColumnItem(column);
    });
  }, [formatColumnItem, columns]);

  // 如果有request方法，为服务端分页
  const handleRequest = useCallback(
    (params: any, sort: any, filter: any) => {
      const filterDatas = filterRef.current?.getFilterValue();
      const sortKeys = Object.keys(sort);
      return request!(
        {
          ...params,
          sort:
            sortKeys.length > 0
              ? `${sortKeys[0]} ${sort[sortKeys[0]] === 'ascend' ? 'ASC' : 'DESC'}`
              : undefined,
          filter: filterDatas,
        },
        sort,
        filter,
      );
    },
    [request],
  );

  const handleFloat = useCallback((dataArr: any[]) => {
    const newArr: any[] = [];
    dataArr.forEach((item) => {
      if (item instanceof Object) {
        for (const key in item) {
          if (typeof item[key] === 'number' && !Number.isInteger(item[key])) {
            const temp = item[key] as number;
            if (typeof dataNumberDecimal === 'number') {
              item[key] = temp.toFixed(dataNumberDecimal);
            }
          }
        }
        newArr.push(item);
      }
    });
    return newArr;
  }, []);

  // 获取表格数据，只有传入queryMethod时才会调用
  const getTableList = useCallback(
    async (queryFormParams: any = queryParams) => {
      if (!queryMethod || request) {
        return;
      }
      setSpin(true);
      let data = [];
      try {
        const reqParams: any = {
          ...queryFormParams,
          filter: undefined,
        };
        //如果是异步分页，需要重写queryFormParams的filter、current、pageSize参数
        const filterResult = filterRef.current?.getFilterValue() || [];
        if (asyncPagination) {
          reqParams.filter = filterParamsFormatter
            ? filterParamsFormatter(filterResult, reqParams)
            : filterResult;
          //重写翻页参数
          const { current = 1, pageSize = 10 } = reqParams;
          reqParams.page = current;
          reqParams.limit = pageSize;
          delete reqParams.current;
          delete reqParams.pageSize;
        }
        const res = await queryMethod(
          queryFormParamsFormatter ? queryFormParamsFormatter(reqParams) : reqParams,
        );
        data = res && res.length ? res : res?.data ?? [];

        if (asyncPagination) {
          const { pagination } = res || {};
          setPaginateConfig({
            current: pagination?.page || 1,
            pageSize: pagination?.limit || 10,
            pageCount: pagination?.total || pagination?.count || 0,
            sort: reqParams?.sort || undefined,
          });
          if (syncURL) {
            const { filter, ...restParams } = reqParams;
            const query = {
              ...location.query,
              ...restParams,
              current: pagination?.page || 1,
              pageSize: pagination?.limit || 10,
              sort: reqParams?.sort || undefined,
            };
            if (!filterResult?.length && query.filter) delete query.filter;
            navigate({
              pathname: location.pathname,
              search: query,
            });
          }
        }
      } catch (error) {
        message.error(`${error}`);
      }

      const arr = handleFloat(data).map((item, index) => ({
        ...item,
        key: item.key ? item.key : index,
      }));
      setDataList(arr);
      setDataSource(arr);
      setSpin(false);
      if (!asyncPagination) {
        setTimeout(() => {
          filterRef.current?.handleFilterList();
        }, 50);
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [
      asyncPagination,
      filterParamsFormatter,
      handleFloat,
      paginateConfig,
      queryFormParamsFormatter,
      queryMethod,
      queryParams,
      request,
      syncURL,
    ],
  );

  useImperativeHandle(
    ref,
    () => ({
      getTableList,
      filterInstance: filterRef.current,
    }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [getTableList, props],
  );

  // 如果使用外部queryMethod
  useEffect(() => {
    if (queryMethod && !dataSourceProps) {
      getTableList({
        ...queryParams,
        ...(asyncPagination
          ? {
            page: paginateConfig.current,
            limit: paginateConfig.pageSize,
            sort: paginateConfig.sort,
          }
          : {}),
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [queryParams]);

  useEffect(() => {
    if (dataSourceProps) {
      const newArr = cloneDeep(dataSourceProps) as any[];
      const arr = handleFloat(newArr).map((item, index) => ({
        ...item,
        key: item.key ? item.key : index,
      }));
      setDataList(arr);
      setDataSource(arr);
      if (!asyncPagination) {
        setTimeout(() => {
          filterRef.current?.handleFilterList();
        }, 50);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dataSourceProps]);

  const fetchExportApi = useCallback(async () => {
    const filterDatas = filterRef.current?.getFilterValue() || [];
    const apiRequest = exportProps?.exportApi || request || queryMethod;
    const params = {
      ...queryParams,
      filter: filterDatas,
    };
    delete params.page;
    delete params.limit;
    return apiRequest!(
      queryFormParamsFormatter ? queryFormParamsFormatter(params) : params,
      {},
      {},
    );
  }, [exportProps?.exportApi, queryFormParamsFormatter, queryMethod, queryParams, request]);

  const handleExport = useCallback(async () => {
    setExportLoading(true);
    try {
      const { data } = await fetchExportApi();
      exportRef.current?.exportCsv(data);
    } catch (error) {
      message.error(`${error}`);
    } finally {
      setExportLoading(false);
    }
  }, [fetchExportApi]);

  const onFilterChange = useCallback(() => {
    const newParams = {
      ...queryParams,
      current: 1,
      sort: paginateConfig.sort,
    };
    getTableList(newParams);
  }, [getTableList, paginateConfig.sort, queryParams]);

  const onTableChange = (pagination: any, filters: any, sorter: any, extraAction: any) => {
    const { action } = extraAction;
    if (action === 'sort') {
      const { field, order } = sorter as any;
      let type: string | undefined = undefined;
      if (order) {
        type = `${field} ${order === 'ascend' ? 'ASC' : 'DESC'}`;
      }
      const newParams = {
        ...queryParams,
        pageSize: pagination.pageSize,
        sort: type,
        current: 1,
      };
      getTableList(newParams);
    } else if (action === 'paginate') {
      const newParams = {
        ...queryParams,
        current: pagination.current,
        pageSize: pagination.pageSize,
        sort: paginateConfig.sort,
      };
      getTableList(newParams);
    }
  };

  const filterFormInitialValues = useMemo(() => {
    const filter = location.query?.[filterQueryKey] as string;
    try {
      if (filter) {
        const strFilterArr = decodeURIComponent(filter);
        const filterArr = JSON.parse(strFilterArr);
        return filterArr || [];
      }
    } catch (error) {
      console.error(error);
      return [];
    }
  }, [filterQueryKey]);

  const toolBarRender = useCallback(() => {
    const renderList: any[] = [];
    const columnsFlat = columnsModified.reduce((acc, cur) => {
      if (cur.children) {
        return [...acc, ...cur.children];
      }
      return [...acc, cur];
    }, []);
    if (showFilter && !request) {
      renderList.push(
        <Filter
          key="$filter"
          ref={filterRef}
          record={dataList}
          columns={columnsFlat}
          syncUrl={syncURL}
          filterSyncUrl={filterSyncUrl}
          setDataSource={setDataSource}
          showFilterButton={true}
          onFilterChange={asyncPagination ? onFilterChange : undefined}
          initalFilter={filterFormInitialValues}
          {...filterProps}
        />,
      );
    }

    if (showExport || showFeishuExport) {
      const asyncExportOverLimit = asyncPagination && paginateConfig.pageCount > 1500000;
      const disableExport = asyncExportOverLimit || exportLoading || !dataSource.length;
      renderList.push(
        <Exports
          key="$exports"
          ref={exportRef}
          datas={request || asyncPagination ? undefined : dataSource}
          columns={columnsFlat}
          disabled={disableExport}
          fetchExportApi={fetchExportApi}
          tooltip={asyncExportOverLimit ? '导出数据量过大' : undefined}
          onExport={request || asyncPagination ? handleExport : undefined}
          loading={exportLoading}
          showCsvExport={showExport}
          showFeishuExport={showFeishuExport}
          {...restExportProps}
        />,
      );
    }

    if (showFullScreen) {
      renderList.push(
        <Tooltip
          key="$full_screen"
          title={isFullScreen ? '退出全屏' : '全屏'}
        >
          <Button type="link" className="table-element-toolbar-button" onClick={handleFullScreen}>
            {isFullScreen ? (
              <FullscreenExitOutlined style={{ width: 24 }} />
            ) : (
              <FullscreenOutlined style={{ width: 24 }} />
            )}
          </Button>
        </Tooltip>,
      );
    }

    if (showDisplayMode) {
      renderList.push(
        <Dropdown
          trigger={['click']}
          key="$displayMode"
          menu={{
            items: [
              {
                key: 'table',
                icon: <TableOutlined />,
                label: '以表格形式展示',
                onClick: () => setDisplayMode('table'),
              },
              {
                key: 'card',
                icon: <ProjectOutlined />,
                label: '以卡片形式展示',
                onClick: () => setDisplayMode('card'),
              },
              {
                key: 'chart',
                icon: <AreaChartOutlined />,
                label: '以图表形式展示',
                onClick: () => setDisplayMode('chart'),
              },
            ],
            selectable: true,
            selectedKeys: [displayMode],
          }}
        >
          <Tooltip title="数据展示方式">
            <Button type="link" className="table-element-toolbar-button">
              <SettingOutlined style={{ width: 24 }} />
            </Button>
          </Tooltip>
        </Dropdown>,
      );
    }
    renderList.push(...extra);
    renderList.unshift(...startExtra);
    return renderList;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    asyncPagination,
    columnsModified,
    dataList,
    dataSource,
    exportLoading,
    extra,
    filterFormInitialValues,
    filterSyncUrl,
    handleExport,
    isFullScreen,
    onFilterChange,
    paginateConfig.pageCount,
    request,
    showDisplayMode,
    showExport,
    showFeishuExport,
    showFilter,
    showFullScreen,
    startExtra
  ]);

  const pagination = {
    ...(asyncPagination
      ? {
        current: paginateConfig?.current,
        pageSize: paginateConfig?.pageSize,
        total: paginateConfig?.pageCount,
      }
      : {}),
    showSizeChanger: true,
    defaultPageSize: 10,
  };

  const renderTable = useMemo(() => {
    return (
      <ProCard
        title={
          headerRender ? (
            headerRender(dataSource, spin)
          ) : (
            <div style={{ color: '#1890ff', fontWeight: 'bold' }}>{header}</div>
          )
        }
        type="default"
        bodyStyle={{ padding: 0 }}
        bordered={isBoolean(cardBordered) ? cardBordered : true}
        extra={toolBarRender()}
        {...cardProps}
      >
        <AnimatePresence exitBeforeEnter>
          {displayMode === 'table' && (
            <motion.div
              key="table"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.3 }}
            >
              <ProTable
                columns={columnsModified}
                request={request ? (...params) => handleRequest(...params) : undefined}
                dataSource={request ? undefined : dataSource}
                loading={request ? undefined : spin}
                options={false}
                cardBordered={false}
                onChange={asyncPagination ? onTableChange : undefined}
                search={search}
                cardProps={{
                  onClick: () => setSelectRowIndex(-1),
                  bodyStyle: { padding: '12px 24px 24px' },
                  style: { borderRadius: 10 },
                  ...tableCardProps,
                }}
                onRow={(record, index: any) => {
                  return {
                    onClick: (event) => {
                      event.stopPropagation();
                      setSelectRowIndex(index);
                    },
                    className: selectRowIndex === index ? 'table-row-selected' : '',
                  };
                }}
                sticky={{
                  offsetHeader: isFullScreen ? -12 : 64,
                  offsetScroll: 0,
                }}
                scroll={{ ...rest.scroll, x: scrollX }}
                pagination={pagination}
                {...rest}
              />
            </motion.div>
          )}
          {displayMode === 'card' && (
            <motion.div
              key="card"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.3 }}
            >
              <CardMode
                columns={columnsModified}
                dataSource={dataSource}
                loading={spin}
                asyncPagination={asyncPagination}
                isTabsTable={isTabsTable}
                pagination={{
                  ...pagination,
                  onChange: asyncPagination
                    ? (current, pageSize) => {
                      const newParams = {
                        ...queryParams,
                        current,
                        pageSize,
                        sort: paginateConfig.sort,
                      };
                      getTableList(newParams);
                    }
                    : undefined,
                }}
                {...cardModeProps}
              />
            </motion.div>
          )}
          {displayMode === 'chart' && (
            <motion.div
              key="chart"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.3 }}
            >
              <ChartMode
                columns={columnsModified}
                dataSource={dataSource}
                loading={spin}
                isTabsTable={isTabsTable}
                asyncPagination={asyncPagination}
                pagination={pagination}
              />
            </motion.div>
          )}
        </AnimatePresence>
      </ProCard>
    );
  }, [
    columnsModified,
    dataSource,
    displayMode,
    header,
    headerRender,
    pagination,
    request,
    rest,
    spin,
  ]);

  if (isFullScreen) {
    return ReactDOM.createPortal(
      <div id="table_element" ref={tableElementRef} className="full-screen">
        {renderTable}
      </div>,
      document.body,
    );
  }

  return (
    <div id="table_element" ref={tableElementRef}>
      {renderTable}
    </div>
  );
});

export default TableElement;
